/** \file chatgpt.c 
 *  \brief chatgpt
 */
#include <assert.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <string>

//#include "speechnls.h" 

#include "het_ringbuf.h" 
#include "het_chatgpt.h"  // <-- 唯一必须包含的头文件

#define MP3MAXFRAMESIZE 4608
static RK_S32 extCodecHandle = -1;
static RK_U32 mp3DecInitCnt = 0;

#define ADEC_CHN_ID 0
#define ADEC_DEV_ID 0

// 用于绑定编码器的音频通道
MPP_CHN_S stBindSrcChn, stBindDestChn;
typedef struct _MP3DecInfo
{
	/* pointers to platform-specific data structures */
	void *FrameHeaderPS;
	void *SideInfoPS;
	void *ScaleFactorInfoPS;
	void *HuffmanInfoPS;
	void *DequantInfoPS;
	void *IMDCTInfoPS;
	void *SubbandInfoPS;

	/* buffer which must be large enough to hold largest possible main_data section */
	unsigned char mainBuf[MAINBUF_SIZE];

	/* special info for "free" bitrate files */
	int freeBitrateFlag;
	int freeBitrateSlots;

	/* user-accessible info */
	int bitrate;
	int nChans;
	int samprate;
	int nGrans;                /* granules per frame */
	int nGranSamps;            /* samples per granule */
	int nSlots;
	int layer;
	int vbr;                    /* is vbr flag */
	uint32_t fSize;             /* file length, no tags */
	uint32_t fCount;            /* frame count */
	char TOC[100];              /* TOC */

	MPEGVersion version;

	int mainDataBegin;
	int mainDataBytes;

	int part23Length[MAX_NGRAN][MAX_NCHAN];
} MP3DecInfo;

typedef struct {
	HMP3Decoder pMp3Dec;
	MP3FrameInfo frameInfo;
	RK_U8 decMp3buf[MP3MAXFRAMESIZE];
	short int decPCMbuf[MP3MAXFRAMESIZE];
	RK_U64 audioPts;
} RK_ADEC_MP3_CTX_S;

static RK_S32 RKAduioMp3DecoderOpen(RK_VOID *pDecoderAttr, RK_VOID **ppDecoder) {
	if (pDecoderAttr == NULL) {
		HET_LOGE("pDecoderAttr is NULL");
		return RK_FAILURE;
	}

	RK_ADEC_MP3_CTX_S *ctx = (RK_ADEC_MP3_CTX_S *)malloc(sizeof(RK_ADEC_MP3_CTX_S));
	if (!ctx) {
		HET_LOGE("malloc adec mp3 ctx failed");
		return RK_FAILURE;
	}

	memset(ctx, 0, sizeof(RK_ADEC_MP3_CTX_S));
	ctx->pMp3Dec = MP3InitDecoder();
	if (!ctx->pMp3Dec) {
		HET_LOGE("malloc adec pMp3Dec failed");
		free(ctx);
		ctx = NULL;
		return RK_FAILURE;
	}

	memset(ctx->decMp3buf, 0, sizeof(ctx->decMp3buf));
	memset(ctx->decPCMbuf, 0, sizeof(ctx->decPCMbuf));

	*ppDecoder = (RK_VOID *)ctx;
	HET_LOGD("RKAduioMp3DecoderOpen SUCCESS");
	return RK_SUCCESS;
}

static RK_S32 RKAduioMp3DecoderClose(RK_VOID *pDecoder) {
	RK_ADEC_MP3_CTX_S *ctx = (RK_ADEC_MP3_CTX_S *)pDecoder;
	if (ctx == NULL)
		return RK_FAILURE;

	if (ctx->pMp3Dec) {
		MP3FreeDecoder(ctx->pMp3Dec);
		ctx->pMp3Dec = NULL;
	}

	if (ctx)
		free(ctx);

	return RK_SUCCESS;
}

static RK_S32 RKAduioMp3DecoderDecode(RK_VOID *pDecoder, RK_VOID *pDecParam) {
	RK_S32 ret = 0;
	RK_ADEC_MP3_CTX_S *ctx = (RK_ADEC_MP3_CTX_S *)pDecoder;
	RK_S32 skip = 0;

	if (ctx == NULL || ctx->pMp3Dec == NULL || pDecParam == NULL)
		return ADEC_DECODER_ERROR;

	AUDIO_ADENC_PARAM_S *pParam = (AUDIO_ADENC_PARAM_S *)pDecParam;
	RK_BOOL eos = RK_FALSE;
	RK_U8 *pInput = NULL;
	RK_S32 inLength = pParam->u32InLen;
	RK_S32 copySize = 0;
	RK_U64 calcPts = 0;

	if ((pParam->pu8InBuf == NULL) || (inLength == 0))
		eos = RK_TRUE;

	copySize =  (inLength <= MP3MAXFRAMESIZE) ? inLength : MP3MAXFRAMESIZE;
	inLength -= copySize;
	memcpy(ctx->decMp3buf, pParam->pu8InBuf, copySize);
	pInput = (RK_U8 *)ctx->decMp3buf;
	if (copySize && (skip = MP3FindSyncWord(pInput, copySize)) < 0) {
		printf("mp3 decode don't find sync word\n");
		pParam->u32InLen = 0;
		return ADEC_DECODER_ERROR;
	}

	copySize -= skip;
	pInput += skip;

	ret = MP3Decode(ctx->pMp3Dec, &pInput, &copySize, ctx->decPCMbuf, 0);
	pParam->u32InLen = inLength + copySize;

	if (ret) {
		if(eos)
		return ADEC_DECODER_EOS;

		pParam->u32InLen = inLength;
		if (ret == ERR_MP3_INDATA_UNDERFLOW) {
		HET_LOGE("mp3 decode input data underflow");
		return ADEC_DECODER_ERROR;
		}

		if(ret == -2) {
		HET_LOGW("mp3 encoded data does not start from the first frame");
		} else {
		HET_LOGE("mp3 decode error, ret = %d", ret);
		return ADEC_DECODER_ERROR;
		}
	}

	MP3GetLastFrameInfo(ctx->pMp3Dec, &ctx->frameInfo);

	MP3DecInfo *mp3DecInfo = (MP3DecInfo *)ctx->pMp3Dec;
	pParam->u32OutLen = mp3DecInfo->nGrans * mp3DecInfo->nGranSamps * ctx->frameInfo.nChans * 2;
	memcpy(pParam->pu8OutBuf, (RK_U8 *)ctx->decPCMbuf, pParam->u32OutLen);

	calcPts = (((RK_U64)pParam->u32OutLen / 2) * 1000000) / ctx->frameInfo.samprate;
	if (pParam->u64InTimeStamp)
		pParam->u64OutTimeStamp = pParam->u64InTimeStamp;
	else if (ctx->audioPts)
		pParam->u64OutTimeStamp = ctx->audioPts + calcPts;

	if (pParam->u64OutTimeStamp)
		ctx->audioPts = pParam->u64OutTimeStamp;
	else {
		ctx->audioPts += calcPts;
	}

	//HET_LOGD("RKAduioMp3DecoderDecode SUCCESS");
	return ADEC_DECODER_OK;
}

static RK_S32 RKAduioMp3DecoderGetFrameInfo(RK_VOID *pDecoder, RK_VOID *pInfo) {
	ADEC_FRAME_INFO_S stFrameInfo;
	RK_ADEC_MP3_CTX_S *ctx = (RK_ADEC_MP3_CTX_S *)pDecoder;

	if (ctx == NULL || pInfo == NULL)
		return RK_FAILURE;

	MP3GetLastFrameInfo(ctx->pMp3Dec, &ctx->frameInfo);

	if (!ctx->frameInfo.bitsPerSample) {
		HET_LOGE("mp3 decode get info failed");
		return RK_FAILURE;
	}

	memset(&stFrameInfo, 0, sizeof(ADEC_FRAME_INFO_S));
	stFrameInfo.u32Channels = ctx->frameInfo.nChans;
	stFrameInfo.u32SampleRate = ctx->frameInfo.samprate;
	stFrameInfo.enBitWidth = AUDIO_BIT_WIDTH_16;
	memcpy(pInfo, &stFrameInfo, sizeof(ADEC_FRAME_INFO_S));
	//HET_LOGD("RKAduioMp3DecoderGetFrameInfo SUCCESS");
	return RK_SUCCESS;
}

RK_S32 RegisterAdecMp3() {
	if (!mp3DecInitCnt) {
		ADEC_DECODER_S adecCtx;
		memset(&adecCtx, 0, sizeof(ADEC_DECODER_S));

		extCodecHandle = -1;
		adecCtx.enType = RK_AUDIO_ID_MP3;
		snprintf((RK_CHAR*)(adecCtx.aszName), sizeof(adecCtx.aszName), "rkaudio1");
		adecCtx.pfnOpenDecoder  = RKAduioMp3DecoderOpen;
		adecCtx.pfnDecodeFrm    = RKAduioMp3DecoderDecode;
		adecCtx.pfnGetFrmInfo   = RKAduioMp3DecoderGetFrameInfo;
		adecCtx.pfnCloseDecoder = RKAduioMp3DecoderClose;
		adecCtx.pfnResetDecoder = RK_NULL;

		HET_LOGD("register ext audio decoder");
		RK_S32 ret = RK_MPI_ADEC_RegisterDecoder(&extCodecHandle, &adecCtx);
		if (ret != RK_SUCCESS) {
			HET_LOGE("adec register decoder fail, ret = 0x%x", ret);
			return RK_FAILURE;
		}
		mp3DecInitCnt++;
	}
	HET_LOGI("RegisterAdecMp3 SUCCESS");
	return RK_SUCCESS;
}

RK_S32 UnRegisterAdecMp3() {
	if (extCodecHandle == -1)
		return RK_SUCCESS;

	if (0 == mp3DecInitCnt) {
		return 0;
	} else if (1 == mp3DecInitCnt) {
		HET_LOGD("unregister ext audio decoder");
		RK_S32 ret = RK_MPI_ADEC_UnRegisterDecoder(extCodecHandle);
		if (ret != RK_SUCCESS) {
			HET_LOGE("adec unregister decoder fail, ret = 0x%x", ret);
			return RK_FAILURE;
		}

		extCodecHandle = -1;
		mp3DecInitCnt--;
	}
	return RK_SUCCESS;
}

RK_S32 init_mpi_adec(RK_S32 s32SampleRate,RK_CODEC_ID_E code_type) {
	HET_LOGD("\n=======%s=======%d\n", __func__,code_type);
	RK_S32 s32ret = 0;
	ADEC_CHN AdChn = ADEC_CHN_ID;
	ADEC_CHN_ATTR_S pstChnAttr;
	memset(&pstChnAttr, 0, sizeof(ADEC_CHN_ATTR_S));

	pstChnAttr.stCodecAttr.enType = (RK_CODEC_ID_E)code_type;
	pstChnAttr.stCodecAttr.u32Channels = 1; // default 1
	pstChnAttr.stCodecAttr.u32SampleRate = s32SampleRate;
	pstChnAttr.stCodecAttr.u32BitPerCodedSample = 4;

	pstChnAttr.enType = (RK_CODEC_ID_E)code_type;
	pstChnAttr.enMode = ADEC_MODE_STREAM; // ADEC_MODE_PACK
	pstChnAttr.u32BufCount = 4;
	pstChnAttr.u32BufSize = 50 * 1024;
	s32ret = RK_MPI_ADEC_CreateChn(AdChn, &pstChnAttr);
	if (s32ret) {
		HET_LOGE("create adec chn %d err:0x%x\n", AdChn, s32ret);
		s32ret = RK_FAILURE;
	}
	HET_LOGD("init_mpi_adec SUCCESS");
	return s32ret;
}

static RK_S32 adec_data_free(void *opaque) {
	if (opaque) {
		free(opaque);
		opaque = RK_NULL;
	}
	return 0;
}

RK_S32 bind_mpi_adec()
{
	RK_S32 ret = 0;
	// adec bind ao
	stBindSrcChn.enModId = RK_ID_ADEC;
	stBindSrcChn.s32DevId = ADEC_DEV_ID;
	stBindSrcChn.s32ChnId = ADEC_CHN_ID;

	stBindDestChn.enModId = RK_ID_AO;
	stBindDestChn.s32DevId = AO_DEV_ID;
	stBindDestChn.s32ChnId = AO_CHN_ID;

	// 3. bind ADEC-AO
	ret = RK_MPI_SYS_Bind(&stBindSrcChn, &stBindDestChn);
	if (ret) {
		HET_LOGE("Bind ADEC[%d] to AO[%d] failed! ret=%d\n", ret, stBindSrcChn.s32ChnId, stBindDestChn.s32ChnId);
		return -1;
	}
	
	g_ctx.ao.bBindAec = RK_TRUE;
	HET_LOGD("bind_mpi_adec SUCCESS");
	return 0;
}

RK_S32 unbind_mpi_adec()
{
	RK_S32 ret = 0;

	// 3. bind ADEC-AO
	ret = RK_MPI_SYS_UnBind(&stBindSrcChn, &stBindDestChn);
	if (ret) {
		HET_LOGE("Bind ADEC[0] to AO[0] failed! ret=%d\n", ret);
		return -1;
	}
	return 0;
}
static RK_BOOL demuxerInited = RK_FALSE;
/**
 * 初始化扩展器
 */
RK_U32 het_mpi_demuxer_init(RK_CODEC_ID_E code_type,RK_CHAR *pInPath){
	RK_U32 ret = 0;
	if(!demuxerInited){
		demuxerInited = RK_TRUE;
		if (g_ctx.ao.s32DeviceSampleRate == 32000 || g_ctx.ao.s32DeviceSampleRate == 44100 || g_ctx.ao.s32DeviceSampleRate == 48000){
			if(g_ctx.ao.stAoAttr.u32PtNumPerFrm != 1152 * 2 * g_ctx.ao.s32DeviceChannel){
				HET_LOGD("het_mpi_demuxer_init 1152 * 2 reinit ao");
				g_ctx.ao.stAoAttr.u32PtNumPerFrm=g_ctx.ao.s32PeriodSize = 1152 * 2 * g_ctx.ao.s32DeviceChannel;
			}
		}
		else{
			if(g_ctx.ao.stAoAttr.u32PtNumPerFrm != 576 * 2 * g_ctx.ao.s32DeviceChannel){
				HET_LOGD("het_mpi_demuxer_init 576 * 2 reinit ao");
				g_ctx.ao.stAoAttr.u32PtNumPerFrm=g_ctx.ao.s32PeriodSize = 576 * 2 * g_ctx.ao.s32DeviceChannel;
			}
		}
		if (code_type == RK_AUDIO_ID_MP3) {
			if(g_ctx.ao.stAoAttr.u32PtNumPerFrm != 1152){
				HET_LOGD("het_mpi_demuxer_init 1152 reinit ao");
				g_ctx.ao.stAoAttr.u32PtNumPerFrm=g_ctx.ao.s32PeriodSize = 1152;
			}
			DemuxerInput stDemuxerInput;
			DemuxerParam tempDemuxerParam;
			memset(&stDemuxerInput, 0, sizeof(DemuxerInput));
			stDemuxerInput.ptr = NULL;
			stDemuxerInput.s8ReadModeFlag = 1;
			stDemuxerInput.s8VideoEnableFlag = 0;
			stDemuxerInput.s8AudioEnableFlag = 1;
			stDemuxerInput.transport = 0;
			stDemuxerInput.rtsp_io_timeout = 0;

			ret = rkdemuxer_init(&g_ctx.ao.demuxerCfg, &stDemuxerInput);
			if (ret) {
				HET_LOGE("rkdemuxer init failed");
				return -1;
			}

			ret = rkdemuxer_get_param(g_ctx.ao.demuxerCfg, pInPath, &tempDemuxerParam);
			if (ret) {
				HET_LOGE("rkdemuxer get param failed");
				return -1;
			}
			
			if (init_mpi_adec(tempDemuxerParam.s32AudioSampleRate, code_type)){
				HET_LOGE("init_mpi_adec mp3 failed");
				return -1;
			}
		} else {
			if (init_mpi_adec(g_ctx.ao.s32DeviceSampleRate, code_type)){
				HET_LOGE("init_mpi_adec auto failed");
				return -1;
			}
		}
		HET_LOGD("het_mpi_demuxer_init SUCCESS");
		ret= bind_mpi_adec();
	}
	return ret;
}

RK_S32 het_mpi_demuxer_deinit(){
	RK_S32 ret = 0;
	if(demuxerInited){
		unbind_mpi_adec();
		RK_MPI_ADEC_DestroyChn(0);
		if (g_ctx.ao.codeType == RK_AUDIO_ID_MP3) {
			if (g_ctx.ao.demuxerCfg){
				rkdemuxer_deinit(&g_ctx.ao.demuxerCfg);
				g_ctx.ao.demuxerCfg = RK_NULL;
			}
		}
		g_ctx.ao.demuxerCfg = RK_NULL;
		g_ctx.ao.bBindAec = RK_FALSE;
		g_ctx.ao.s32PeriodSize=1024;
		demuxerInited = RK_FALSE;
	}
	return ret;
}

// 获取文件扩展名
const char* get_file_extension(const char *filename) {
    const char *dot = strrchr(filename, '.');
    if (!dot || dot == filename) return "";
    return dot + 1;
}

// 根据文件扩展名获取音频类型
RK_CODEC_ID_E get_audio_type(const char *filename) {
    const char *ext = get_file_extension(filename);

    if (strcasecmp(ext, "mp3") == 0) {
        return RK_AUDIO_ID_MP3;
    }  else if (strcasecmp(ext, "g711a") == 0) {
        return RK_AUDIO_ID_PCM_ALAW;
    }  else{
        return RK_AUDIO_ID_AutoDetect;
    }
}
RK_S32 het_adec_audio(RK_CHAR *pInPath){
	RK_S32 ret = 0;
	RK_U8 *srcData = RK_NULL;
	RK_S32 srcSize = 0;
	RK_S32 totalSize = 0;
	RK_S32 pktEos = 0;
	RK_U64 timeStamp = 0;
	RK_S32 count = 0;
	AUDIO_STREAM_S stAudioStream;
	RK_CODEC_ID_E code_type;
	FILE *adec_file;
	if (pInPath) {
		adec_file = fopen(pInPath, "rb");
		if (!adec_file) {
			HET_LOGE("ERROR: open file: %s fail, exit\n", pInPath);
			return 0;
		}
		code_type = get_audio_type(pInPath);
		HET_LOGE("open file: type %s\n",  code_type == RK_AUDIO_ID_MP3 ? "mp3" : code_type == RK_AUDIO_ID_PCM_ALAW ? "g711a" :"auto");
	}
	ao_run = RK_FALSE;
	usleep(100000);
	if(code_type == RK_AUDIO_ID_MP3){
		ret = RegisterAdecMp3();
		if (ret != 0 ){
			HET_LOGE("ERROR: RegisterAdecMp3 fail, exit %d\n", ret);
			ao_run = RK_TRUE;
			return -1;
		}
	}
	
	ret = het_mpi_demuxer_init(code_type,pInPath);
	if (ret != 0 ){
		HET_LOGE("ERROR: het_mpi_demuxer_init fail, exit %d\n", ret);
		ao_run = RK_TRUE;
		//UnRegisterAdecMp3();
		return ret;
	}
	if (RK_MPI_AMIX_SetControl(AO_CHN_ID, (char *)"DAC Control Manually", (char *)"On") != RK_SUCCESS) {
		RK_LOGE("adec set DAC Control Manually fail");
	}
	HET_LOGI("pa on run[%d] play[%d]\r\n",global_run,in_play);
	while (global_run && in_play) {
		if (code_type == RK_AUDIO_ID_MP3) {
			DemuxerPacket outPacket;
			ret = rkdemuxer_read_one_audio_packet(g_ctx.ao.demuxerCfg, &outPacket);
			if (!ret) {
				srcData = (unsigned char *)outPacket.s8PacketData;
				srcSize = outPacket.s32PacketSize;
				totalSize += srcSize;
				HET_LOGI("mp3 play size %d total %d!",srcSize,totalSize);
			} else{
				HET_LOGI("mp3 error %d!",ret);
				//continue;
			}
		} else {
			srcData = (RK_U8*)calloc(g_ctx.ao.s32PeriodSize, sizeof(RK_U8));
			memset(srcData, 0, g_ctx.ao.s32PeriodSize);

			srcSize = fread(srcData, 1, g_ctx.ao.s32PeriodSize, adec_file);
			totalSize += srcSize;
		}
	
		if (srcSize == 0 || srcData == RK_NULL) {
			HET_LOGI("read eos packet, now send eos packet!");
			pktEos = 1;
		}

		if (pktEos) {
			RK_MPI_ADEC_SendEndOfStream(ADEC_CHN_ID, RK_FALSE);
			// free srcData here, otherwise it will be leaked
			HET_LOGI("send pktEos packet total %d!",totalSize);
			free(srcData);
			pktEos = 0;
			break;
		} else {
			stAudioStream.u32Len = srcSize;
			stAudioStream.u64TimeStamp = timeStamp;
			stAudioStream.u32Seq = ++count;
			stAudioStream.bBypassMbBlk = RK_TRUE;
			MB_EXT_CONFIG_S extConfig = {0};
			extConfig.pFreeCB = adec_data_free;
			extConfig.pOpaque = srcData;
			extConfig.pu8VirAddr = srcData;
			extConfig.u64Size = srcSize;
			HET_LOGI("RK_MPI_SYS_CreateMB +++");
			ret = RK_MPI_SYS_CreateMB(&(stAudioStream.pMbBlk), &extConfig);
			HET_LOGI("RK_MPI_SYS_CreateMB ---");
			if (RK_SUCCESS == ret) {
__RETRY:
				HET_LOGI("RK_MPI_ADEC_SendStream +++");
				ret = RK_MPI_ADEC_SendStream(ADEC_CHN_ID, &stAudioStream, RK_TRUE);
				HET_LOGI("RK_MPI_ADEC_SendStream ---");
				if (ret != RK_SUCCESS) {
					HET_LOGE("fail to send adec stream.");
					goto __RETRY;
				}
				HET_LOGI("RK_MPI_MB_ReleaseMB +++");
				RK_MPI_MB_ReleaseMB(stAudioStream.pMbBlk);
				HET_LOGI("RK_MPI_MB_ReleaseMB ---");
			}
		}
		srcSize = 0;
		srcData = RK_NULL;
		timeStamp++;
	}
	HET_LOGI("WaitEos b");
	RK_MPI_AO_WaitEos(AO_DEV_ID, AO_CHN_ID, -1);
	HET_LOGI("WaitEos e");
	if (RK_MPI_AMIX_SetControl(AO_CHN_ID, (char *)"DAC Control Manually", (char *)"Off") != RK_SUCCESS) {
		RK_LOGE("adec set DAC Control Manually fail");
	}
	HET_LOGI("pa off run[%d] play[%d]\r\n",global_run,in_play);
	if (adec_file) {
		fclose(adec_file);
		adec_file = RK_NULL;
	};
	het_mpi_demuxer_deinit();
	UnRegisterAdecMp3();
	ao_run = RK_TRUE;
	HET_LOGI("het_play_audio SUCCESS");
	return 0;

}